package listen

import (
	"context"
	"ezcloud/gw/internal/conf"
	"ezcloud/gw/internal/log"
	"ezcloud/gw/pkg/protocol"
	"fmt"
	"net"
	"os"
	"sync/atomic"
	"time"
)

const keepaliveTime = 5 * time.Second

type TcpListener struct {
	config   conf.ListenerConfig
	listener net.Listener
	protocol protocol.Protocol
	sequence uint64
}

func (L *TcpListener) Start() error {
	var err error
	var lc = &net.ListenConfig{}
	lc.KeepAlive = keepaliveTime
	L.listener, err = lc.Listen(context.Background(), "tcp", fmt.Sprintf("%s:%d", L.config.Host, L.config.Port))
	if err != nil {
		log.Errorf("tcp listen [%s:%d] error: %v", L.config.Host, L.config.Port, err)
		return err
	}
	log.Infof("tcp listen [%s:%d] ...", L.config.Host, L.config.Port)
	L.protocol = protocol.NewProtocol(L.config.Protocol)
	return L.protocol.Start(L)
}

func (L *TcpListener) Stop() error {
	return L.protocol.Stop()
}

func (L *TcpListener) Accept() (net.Conn, error) {
	c, err := L.listener.Accept()
	if err != nil {
		log.Errorf("TcpListener accept error: %v", err)
		return nil, err
	}
	return conf.NewTcpConnWrap(c, L.genShortId()), err
}

func (L *TcpListener) genShortId() string {
	// PROCESS_ID_LEN + SEQUENCE
	return fmt.Sprintf("%d-%d", os.Getpid(), atomic.AddUint64(&L.sequence, 1))
}

func (L *TcpListener) Close() error {
	return L.listener.Close()
}

func (L *TcpListener) Addr() net.Addr {
	return L.listener.Addr()
}
